package com.moli.iov.real.service.impl;

import com.moli.iov.alarm.model.po.AlarmInfo;
import com.moli.iov.alarm.remote.IAlarmRemoteService;
import com.moli.iov.cache.RedisUtil;
import com.moli.iov.contant.RealContant;
import com.moli.iov.protocol.model.dto.realtime.RealTimeInfoDto;
import com.moli.iov.protocol.model.realtime.ExtendVehicleState;
import com.moli.iov.protocol.model.realtime.RealTimeInfo;
import com.moli.iov.protocol.model.realtime.RealTimeInfoReq;
import com.moli.iov.protocol.model.realtime.VehicleAllReq;
import com.moli.iov.protocol.util.RealTimeInfoUtil;
import com.moli.iov.real.model.res.VehicleLocationDto;
import com.moli.iov.real.model.res.VehicleStatusDto;
import com.moli.iov.real.service.ICacheService;
import com.moli.iov.real.service.IRealService;
import com.moli.iov.real.service.RealTimeService;
import com.moli.iov.rest.RestResponse;
import com.moli.iov.util.JsonUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;

import com.moli.iov.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Slf4j
@Service("realService")
public class RealServiceImpl implements IRealService {

    @Resource
    ICacheService cacheService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    RealTimeService realTimeService;

    @Resource
    IAlarmRemoteService alarmRemoteService;

    public final static String KEY_ONLINE_TIME = "IOV:VEHICLE:ONLINE";

    @Override
    public RestResponse<Date> getLastOnlineTime(String vin) {
        String time = redisUtil.hget(KEY_ONLINE_TIME, vin);
        if (!StringUtils.isEmpty(time)) {
            return RestResponse.success(new Date(Long.parseLong(time)));
        }
        return RestResponse.success();
    }

    private RestResponse checkVinList(List<String> vinList) {
        if (vinList == null || vinList.size() < 1 || vinList.contains(null)) {
            return RestResponse.paramFailure("入參异常，请检查参数");
        }
        return null;
    }

    private RestResponse checkVin(String vin) {
        if (StringUtils.isEmpty(vin)) {
            return RestResponse.paramFailure("入參异常，请检查参数");
        }
        return null;
    }

    @Override
    public RestResponse<String> deleteAllOnlineVins() {
        try {
            redisUtil.delete(RealContant.KEY_ONLINE);
        } catch (Exception e) {
            return RestResponse.failure("删除失败");
        }
        return RestResponse.success();
    }

    /**
     * 获取所有车辆实时状态
     * @return
     * @throws Exception
     */
//    @Override
//    public RestResponse<List<RealTimeInfoDto>> listAllRealTimeInfo() {
//        try {
//            return RestResponse.success(queryAllRealTimeInfoList());
//        } catch (Exception e) {
//            log.error("查询全量车辆状态异常,{}",e.getMessage());
////            e.printStackTrace();
//            return RestResponse.failure("查询全量车辆状态异常");
//        }
//    }

    /**
     * 根据车架号集合获取在线vin集合
     *
     * @param vinList
     * @return
     * @throws Exception
     */
    @Override
    public RestResponse<List<String>> isOnlineList(List<String> vinList) throws Exception {
        long start = System.currentTimeMillis();
        //入参验证
        RestResponse res = checkVinList(vinList);
        if (res != null) {
//            log.info("[查询在线车辆集合][校验失败]",res.getMessage());
            return res;
        }

        log.info("[查询在线车辆集合][vinList:{}]", vinList.size());

        List<String> list = this.queryOnlineVehicle(vinList);
        List<String> result = new ArrayList<>();
        for (String vinAndTime : list) {
            if(!StringUtils.isEmpty(vinAndTime) && vinAndTime.indexOf("_")>0){
                String vin = vinAndTime.split("_")[0];
                result.add(vin);
            }
        }
        RestResponse<List<String>> resList = RestResponse.success(result);
        long end = System.currentTimeMillis();
        log.info("执行时长:{}", end - start);
        return resList;
    }

    /**
     * 获取全量实时信息数据
     *
     * @return
     * @throws Exception
     */
    private List<RealTimeInfoDto> queryAllRealTimeInfoList() throws Exception {
        Map<String, String> map = cacheService.queryAllRealTimeInfoStringMap();
        if (map != null && map.size() > 0) {
            List<RealTimeInfoDto> list = new ArrayList<>();
            for (String json : map.values()) {
                RealTimeInfoDto dto = this.parseJson2RealTimeInfoDto(json);
                if (dto != null) {
                    list.add(dto);
                }

            }
            return list;
        }
        return null;
    }

    /**
     * 根据车架号集合获取定位状态map
     *
     * @param vinList
     * @return
     * @throws Exception
     */
    @Override
    public RestResponse<Map<String, Boolean>> isLocationVinMap(List<String> vinList) throws Exception {

        //入参验证
        RestResponse res = checkVinList(vinList);
        if (res != null) {
            return res;
        }


        Map<String, Boolean> result = new HashMap<>();
        for (String vin : vinList) {
            result.put(vin, false);
        }
        result.putAll(cacheService.getLocationMap(vinList));

        return RestResponse.success(result);

    }


    /**
     * 获取全量在线车架号集合
     *
     * @return
     * @throws Exception
     */
    @Override
    public RestResponse<List<String>> queryAllOnlineList() throws Exception {
        Map<String, String> map = cacheService.queryAllOnlineMap();
        if (map == null || map.size() < 1) {
            log.info("未查询到任何在线车辆");
            return RestResponse.success();
        }
        List<String> vinList = new ArrayList<>();
        vinList.addAll(map.keySet());
        return RestResponse.success(vinList);
    }

    /**
     * 批量查询车辆上下线状态
     * param vinList
     * return Map<String,Boolean>
     */
    @Override
    public RestResponse<Map<String, Boolean>> isOnlineMap(List<String> vinList) throws Exception {

        //入参验证
        RestResponse res = checkVinList(vinList);
        if (res != null) {
            return res;
        }
        log.info("查询车辆在线状态MAP,参数:{}", vinList);

        List<String> offLineList = vinList;

        //获取在线vin集合
        List<String> onlineList = this.queryOnlineVehicle(vinList);
        if (onlineList == null) {
            onlineList = new ArrayList<>();
        }

        Set<String> onLineSet = new HashSet<>();
        if (onlineList.size() > 0) {
            for (String s : onlineList) {
                if(!StringUtils.isEmpty(s)){
                    onLineSet.add(s.split("_")[0]);
                }
            }
        }

        Map<String, Boolean> map = new HashMap<>();

        //如不存在与Set集合内则视为下线、存在即在线
        for (String vin : vinList) {
            map.put(vin, onLineSet.contains(vin));
        }
        log.info("查询车辆在线状态MAP,结果:{}", map);
        RestResponse<Map<String, Boolean>> result = RestResponse.success(map);
        return result;
    }

    private List<String> queryOnlineVehicle(List<String> vinList) throws Exception {
        List<String> list = cacheService.queryOnlineList(vinList);
        return list;
    }

    /**
     * 查询单个车辆在线状态
     * param vin
     * return Boolean
     * true :在线   ；  false:下线。
     */
    @Override
    public RestResponse<Boolean> isOnline(String vin) throws Exception {

        //入参校验
        RestResponse restRes = checkVin(vin);
        if (restRes != null) {
            return restRes;
        }

        //缓存查询车辆是否在线
        String tmp = cacheService.getOnline(vin);
        if (StringUtils.isEmpty(tmp)) {
            //未查询到数据 则车辆不在线
            log.error("未查询到相关在线数据，车架号:{}", vin);
            return RestResponse.success(false);
        }
        return RestResponse.success(true);
    }


    /**
     * 查询单个车辆实时数据
     * param vin
     * return RealTimeInfo
     */
//    @Override
//    public RestResponse<RealTimeInfoDto> getRealTimeInfo(String vin) throws Exception {
//
//        //入参校验
//        RestResponse restRes = checkVin(vin);
//        if (restRes != null) {
//            return restRes;
//        }
//
//        //缓存查询车辆实时状态数据
//        String realTimeInfoJson = cacheService.getRealTimeInfoStringByVin(vin);
//
////        log.info("[实时报文查询][vin={} 的实时数据：{}]", vin, realTimeInfoJson);
//        if (StringUtils.isEmpty(realTimeInfoJson)) {
//            log.info("[实时报文查询][未查到：vin={} 的实时数据]", vin);
//        }
//        RealTimeInfoDto dto = this.parseJson2RealTimeInfoDto(realTimeInfoJson);
//        RestResponse<RealTimeInfoDto> result = RestResponse.success(dto);
//        return result;
//    }

//    /**
//     * 根据车架号集合获取 key:vin,value:RealTimeInfo Map
//     * @param vins
//     * @return
//     * @throws Exception
//     */
//    @Override
//    public RestResponse<Map<String, RealTimeInfoDto>> getRealTimeInfoMap(List<String> vins) throws Exception {
//
//        //入参验证
//        RestResponse restRes = checkVinList(vins);
//        if (restRes != null) {
//            return restRes;
//        }
//        log.info("查询实时信息MAP,参数:{}",vins);
//
//        //获取实时报文json集合
//        List<String> res = cacheService.queryRealTimeInfoStringListByVins(vins);
//        if (res != null && res.size() > 0) {
//            Map<String, RealTimeInfoDto> map = new HashMap<>();
//            for (String realTimeInfoJson : res) {
////                log.info("[实时报文查询][vin={} 的实时数据：{}]", vins, realTimeInfoJson);
//                if (StringUtils.isEmpty(realTimeInfoJson)) {
//                    log.error("[实时报文查询][未查到：vin={} 的实时数据]", vins);
//                } else {
//                    RealTimeInfoDto dto = this.parseJson2RealTimeInfoDto(realTimeInfoJson);
//                    map.put(dto.getVin(), dto);
//                }
//            }
//            return RestResponse.success(map);
//        }
//        log.error("[实时报文查询][未能查到：vin={} 的实时数据]", vins);
//        return RestResponse.failure("未查询到实时数据");
//
//    }

//    /**
//     * 根据车架号集合获取实时报文集合
//     * @param vins
//     * @return
//     * @throws Exception
//     */
//    @Override
//    public RestResponse<List<RealTimeInfoDto>> getRealTimeInfoList(List<String> vins) throws Exception {
//
//        //入参验证
//        RestResponse restRes = checkVinList(vins);
//        if (restRes != null) {
//            return restRes;
//        }
//
//        //获取实时报文json集合
//        List<String> res = cacheService.queryRealTimeInfoStringListByVins(vins);
//        if (res != null && res.size() > 0) {
//            List<RealTimeInfoDto> list = new ArrayList<>();
//            for (String realTimeInfoJson : res) {
////                log.info("[实时报文查询][vin={} 的实时数据：{}]", vins, realTimeInfoJson);
//                if (StringUtils.isEmpty(realTimeInfoJson)) {
//                    log.info("[实时报文查询][未查到：vin={} 的实时数据]", vins);
//                } else {
//                    RealTimeInfoDto dto = parseJson2RealTimeInfoDto(realTimeInfoJson);
//                    if (dto != null) {
//                        list.add(dto);
//                    }
//                }
//            }
//            return RestResponse.success(list);
//        }
//
//        return RestResponse.failure("未查询到实时数据");
//    }
    private RealTimeInfoDto parseJson2RealTimeInfoDto(String json) throws Exception {
        try {
            RealTimeInfoDto realTime = JsonUtils.parse(json, RealTimeInfoDto.class);
            return realTime;
        } catch (Exception e) {
            log.error("[parseJson2Real][parse-error][json:{}][mess:{}]", json, e.getMessage());
            return null;
        }
    }

    /**
     * 根据车架号集合获取在线数
     *
     * @param vinList
     * @return
     * @throws Exception
     */
    @Override
    public RestResponse<Integer> getVehicleOnlineCount(List<String> vinList) throws Exception {

        //入参验证
        RestResponse restRes = checkVinList(vinList);
        if (restRes != null) {
            return restRes;
        }

        List<String> list = this.queryOnlineVehicle(vinList);
        if (list == null) {
            log.error("未查询到任何在线车辆,参数:{}", vinList);
            return RestResponse.success(0);
        } else {
            return RestResponse.success(list.size());
        }
    }

    @Override
    public RestResponse<List<String>> getLocationVinList() {
        List<String> res = cacheService.getLocationVinList();
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<Map<String, VehicleStatusDto>> getVehicleStatusByVin(List<String> vinList) {
        long start = System.currentTimeMillis();
        if (vinList == null && vinList.size() <= 0) {
            log.info("[车架号集合不能为空]");
            return RestResponse.failure("车架号集合不能为空");
        }

        Map<String, Boolean> onlineMap = new HashMap<>();
        try {
            RestResponse<Map<String, Boolean>> onlineMapRes = isOnlineMap(vinList);
            if (onlineMapRes != null) {
                onlineMap = onlineMapRes.getData();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Map<String, Double> odoMap = getOdoMap(vinList);
        List<RealTimeInfo> res = realTimeService.listRealTimeInfo(vinList);
        if (res != null && res.size() > 0) {
            Map<String, VehicleStatusDto> map = new HashMap<>();
            for (RealTimeInfo re : res) {
                if (re != null && re.getRealTimeInfoReq() != null && !StringUtils.isEmpty(re.getVin())) {
                    RealTimeInfoReq req = re.getRealTimeInfoReq();

                    VehicleStatusDto dto = new VehicleStatusDto();

                    if (req.getCollectDate() != null) {
                        dto.setReportDate(req.getCollectDate().getDate());
                    }

                    if (req.getExtendReq() != null && req.getExtendReq().getextendVehicleState() != null) {
                        ExtendVehicleState vehicleState = req.getExtendReq().extendVehicleState;
                        dto.setDynamicState(vehicleState.getDynamicState());
                        dto.setExtendLeasing(vehicleState.getExtendLeasing());
                        dto.setExtendPowerGear(vehicleState.getExtendPowerGear());
                        dto.setGpsOdo((double) RealTimeInfoUtil.getGpsOde(re));
                        dto.setPhysicalKeyState(vehicleState.getPhysicalKeyState());
                    }

                    VehicleAllReq allReq = req.getVehicleAllReq();
                    if (allReq != null) {
                        dto.setMeterOdo(allReq.getOdometer());
                        dto.setOdo(odoMap.get(re.getVin()) + allReq.getOdometer());
                    } else {
                        dto.setOdo(odoMap.get(re.getVin()));
                    }

                    dto.setVin(re.getVin());
                    dto.setOnlineState(onlineMap.get(re.getVin()));
                    map.put(re.getVin(), dto);
                }
            }
            long end = System.currentTimeMillis();
            log.info("执行时长:{}", end - start);
            return RestResponse.success(map);
        }


//        if(vinList!=null && vinList.size()>0){
//            Map<String,VehicleStatusDto> map  =new HashMap<>();
//            for (String s : vinList) {
//
//                dto.setDynamicState(CommonLockTag.CLOSE);
//                dto.setExtendLeasing(ExtendLeasingModelTag.NO);
//                dto.setExtendPowerGear(ExtendPowerGearTag.OFF);
//                dto.setGpsOdo(1314D);
//                dto.setMeterOdo(1267D);
//                dto.setOnlineState(true);
//                dto.setOdo(1578D);
//                dto.setReportDate(new Date());
//                dto.setVin(s);
//                dto.setPhysicalKeyState(CommonEnableTag.OPEN);
//                map.put(s,dto);
//            }
//            return RestResponse.success(map);
//        }
        return RestResponse.success();
    }

    private Map<String, Double> getOdoMap(List<String> vinList) {

        Map<String, Double> map = new HashMap<>();
        if (vinList == null || vinList.size() <= 0) {
            return map;
        }

        for (String vin : vinList) {
            map.put(vin, 0D);
        }
        long start = System.currentTimeMillis();
        RestResponse<List<AlarmInfo>> res = alarmRemoteService.listMileageExceptionChange(vinList);
        if (res != null && res.flag && res.getData() != null && res.getData().size() > 0) {
            List<AlarmInfo> alarmList = res.getData();
            for (AlarmInfo alarmInfo : alarmList) {
                if (alarmInfo != null && alarmInfo.getMileageExceptionChange() != null) {
                    Double dm = alarmInfo.getMileageExceptionChange().getDifferenceMileage();
                    map.put(alarmInfo.getVin(), map.get(alarmInfo.getVin()) + dm);
                }
            }
        }
        long end = System.currentTimeMillis();
        log.info("执行时长:{}", end - start);
        return map;
    }

    @Override
    public RestResponse<Map<String, VehicleStatusDto>> getAllVehicleStatus() {
        long start = System.currentTimeMillis();
        List<RealTimeInfo> res = realTimeService.listRealTimeInfo(null);

        if (res != null && res.size() > 0) {
            Map<String, VehicleStatusDto> map = new HashMap<>();

            List<String> vinList = new ArrayList<>();
            for (RealTimeInfo re : res) {
                if (re != null && re.getRealTimeInfoReq() != null && !StringUtils.isEmpty(re.getVin())) {
                    vinList.add(re.getVin());
                }
            }

            Map<String, Boolean> onlineMap = new HashMap<>();
            try {
                RestResponse<Map<String, Boolean>> onlineMapRes = isOnlineMap(vinList);
                if (onlineMapRes != null) {
                    onlineMap = onlineMapRes.getData();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            Map<String, Double> odoMap = getOdoMap(vinList);

            for (RealTimeInfo re : res) {
                if (re != null && re.getRealTimeInfoReq() != null && !StringUtils.isEmpty(re.getVin())) {
                    RealTimeInfoReq req = re.getRealTimeInfoReq();

                    VehicleStatusDto dto = new VehicleStatusDto();

                    if (req.getExtendReq() != null && req.getExtendReq().getextendVehicleState() != null) {
                        ExtendVehicleState vehicleState = req.getExtendReq().extendVehicleState;
                        dto.setDynamicState(vehicleState.getDynamicState());
                        dto.setExtendLeasing(vehicleState.getExtendLeasing());
                        dto.setExtendPowerGear(vehicleState.getExtendPowerGear());
                        dto.setGpsOdo((double) RealTimeInfoUtil.getGpsOde(re));
                        dto.setPhysicalKeyState(vehicleState.getPhysicalKeyState());
                    }

                    VehicleAllReq allReq = req.getVehicleAllReq();
                    if (allReq != null) {
                        dto.setMeterOdo(allReq.getOdometer());
                    }

                    dto.setVin(re.getVin());

                    dto.setOnlineState(onlineMap.get(re.getVin()));
                    dto.setOdo(odoMap.get(re.getVin()));

                    map.put(re.getVin(), dto);
                }
            }
            long end = System.currentTimeMillis();
            log.info("执行时长:{}", end - start);
            return RestResponse.success(map);
        }
        return null;
    }

    @Override
    public RestResponse<RealTimeInfoReq> getRealTimeInfo(String vin) throws Exception {
        long start = System.currentTimeMillis();
        RealTimeInfoReq res = realTimeService.getRealTimeInfoReq(vin);
        long end = System.currentTimeMillis();
        log.info("执行时长:{}", end - start);
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<RealTimeInfo> getRealTime(String vin) throws Exception {
        long start = System.currentTimeMillis();
        RealTimeInfo res = realTimeService.getRealTimeInfo(vin);
        long end = System.currentTimeMillis();
        log.info("执行时长:{}", end - start);
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<List<RealTimeInfo>> listRealTimeInfo(List<String> vins) throws Exception {
        long start = System.currentTimeMillis();
        List<RealTimeInfo> res = realTimeService.listRealTimeInfo(vins);
        long end = System.currentTimeMillis();
        log.info("执行时长:{}", end - start);
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<Date> getLastReportTime(String vin) throws Exception {
        String time = redisUtil.hget(KEY_ONLINE_TIME, vin);
        if (!StringUtils.isEmpty(time)) {
            Long dateLong = Long.parseLong(time.split("_")[1]);
            return RestResponse.success(new Date(dateLong));
        }
        return RestResponse.success();
//        long start = System.currentTimeMillis();
//        Date res = realTimeService.getLastReportTime(vin);
//        long end = System.currentTimeMillis();
//        log.info("执行时长:{}{}",vin,end-start,res);
//        return RestResponse.success(res);
    }

    @Override
    public RestResponse<Map<String, Date>> getLastReportTimeMap(List<String> list) throws Exception {
        if (list != null && list.size() > 0) {
            List<String> resList = redisUtil.hgetString(KEY_ONLINE_TIME, list);
            if (resList != null && resList.size() > 0) {
                Map<String, Date> res = new HashMap<>();
                for (String s : resList) {
                    if (!StringUtils.isEmpty(s)) {
                        String[] arr = s.split("_");
                        if (arr != null && arr.length == 2) {
                            res.put(arr[0], new Date(Long.parseLong(arr[1])));
                        }
                    }
                }
                return RestResponse.success(res);
            }
        }
        return RestResponse.success();
    }

    /**
     * 根据车架号获取当前坐标
     *
     * @param vin
     * @return
     * @throws Exception
     */
    @Override
    public RestResponse<VehicleLocationDto> getLocation(String vin) throws Exception {
        if (StringUtils.isEmpty(vin)) {
            return RestResponse.failure("车架号不能为空");
        }
        RealTimeInfo info = realTimeService.getRealTimeInfo(vin);
        if (info != null) {
            VehicleLocationDto dto = new VehicleLocationDto();
            dto.setVin(vin);
            dto.setLatitude(info.getLatitude());
            dto.setLongitude(info.getLongitude());
            dto.setReportTime(info.getGpsReportTime());
            return RestResponse.success(dto);
        }
        return RestResponse.success();
    }

    @Override
    public RestResponse<Map<String, Integer>> getDynamicStateMap(List<String> vinList) {
        log.info("调用获取动力状态接口:{}", (vinList == null ? 0 : vinList.size()));
        Map<String, Integer> res = cacheService.getDynamicStateMap(vinList);
        log.info("调用获取动力状态返回:{}", (res == null ? 0 : res.size()));
        return RestResponse.success(res);
    }
}
